package com.edgardeng.generator.service;

import com.alibaba.fastjson.JSON;
import com.edgardeng.generator.entity.FileTree;
import com.edgardeng.generator.entity.Module;
import com.edgardeng.utils.GenUtils;
import com.edgardeng.utils.JsonUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 代码生成器
 */
@Service
public class FileGeneratorService {

    public boolean generateModule(Module module) {
        try {
            String applicationName = module.getName().replace("-", "");
            String nameLowerCase = module.getName().toLowerCase();
            // 1 root
            String root = module.getDir() + File.separator + nameLowerCase;
            System.out.println("root:" + root);

            String src = root + File.separator + "src";
            String main = src + File.separator + "main";
            String java = main + File.separator + "java";
            String resources = main + File.separator + "resources";
            String test = src + File.separator + "test";
            String testJava = test + File.separator + "java";
            try {
                mkdirs(new String[]{root, src, main, java, resources, test, testJava});
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }

            // 2 packageName
            String[] packageNames = module.getPackageName().split("\\."); // .需要做转义

            String javaPackage = java + "";
            String testjavaPackage = testJava + "";
            for (String n : packageNames) {
                javaPackage = javaPackage + File.separator + n;
                testjavaPackage = testjavaPackage + File.separator + n;
                try {
                    new File(javaPackage).mkdir();
                    new File(testjavaPackage).mkdir();
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage());
                }
            }

            String[] folds = createFold4Module(javaPackage, resources);

            // 2 生成 部分代码
           // pom.xml
            Map<String, Object> map =  createHashMap(module);
            System.out.println(map.toString());

            String[] files = new String[]{
                    resources + File.separator + "banner.txt",
                    resources + File.separator + "bootstrap.yml",
                    root + File.separator + "pom.xml",
                    javaPackage + File.separator + applicationName + "Application.java",
                    folds[5] + File.separator + "StartedUpRunner.java",
                    folds[1] + File.separator + "ResourceServerConfigure.java",
                    folds[1] + File.separator + "JupiterWebConfigure.java",
                    testjavaPackage + File.separator + applicationName + "TestApplication.java"
            };

            String[] tmps = new String[]{
                    "module/banner.ftl",
                    "module/bootstrap.ftl",
                    "module/pom.ftl",
                    "module/application.ftl",
                    "module/runner.ftl",
                    "module/configure.ftl",
                    "module/webConfigure.ftl",
                    "module/test.ftl",
            };

            int len = files.length;
            for (int i = 0; i < len; i++) {
                try {
                    GenUtils.freemarkerTemp2File(tmps[i], map, files[i]);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return true;
    }

    /**
     * erver, model_configure, model_ctr, model_entity, model_map, model_runner, model_service, model_impl, resources_map
     *
     * @param javaPackage resources
     */
    private String[] createFold4Module(String javaPackage, String resources) {
        System.out.println(">> createFold4Module with javaPackage:" + javaPackage + ", resources:" + resources);

        String server = javaPackage + File.separator + "server";
        String model_configure = javaPackage + File.separator + "configure";
        String model_ctr = javaPackage + File.separator + "controller";
        String model_runner = javaPackage + File.separator + "runner";
        String model_entity = javaPackage + File.separator + "entity";
        String model_map = javaPackage + File.separator + "mapper";
        String model_service = javaPackage + File.separator + "service";
        String model_impl = model_service + File.separator + "impl";
        String resources_map = resources + File.separator + "mapper";
        String[] folds = new String[]{server, model_configure, model_ctr, model_entity, model_map, model_runner, model_service, model_impl, resources_map};
        mkdirs(folds);
        return folds;
    }


    private Map<String, Object> createHashMap(Module module) {
        String name = module.getName();
        String nameLowerCase = name.toLowerCase();
        String applicationName = name.replace("-", "");
        // pom.xml
        Map<String, Object> map = new HashMap<>();
        map.put("moduleName", name);
        map.put("moduleNameLower", nameLowerCase);
        map.put("packageName", module.getPackageName());
        map.put("moduleDesc", module.getDesc());
        map.put("applicationName", applicationName);
        map.put("isNeedCommon", module.getIsNeedCommon());

        return map;
    }

    private void genModuleAuth(Module module, Map<String, Object> map) {

        String nameLowerCase = module.getName().toLowerCase();
        // create java resource
        String[] dirs = createJavaAndResources4Module(module.getPath(), "jupiter-auth", true);
        String moduleRoot = dirs[0];
        String javaPackage = createJavaPackage4Module(dirs[1], module.getPackageName());
        String resources = dirs[2];
        String testJavaPackage = createJavaPackage4Module(dirs[3], module.getPackageName());
        String[] folds = createFold4Module(javaPackage, resources);
        String[] files = new String[]{
                resources + File.separator + "banner.txt",
                resources + File.separator + "bootstrap.yml.ftl",
                moduleRoot + File.separator + "pom.xml",
                javaPackage + File.separator + map.get("applicationName") + "Application.java"
        };
        String[] tmps = new String[]{
                "module/banner.ftl",
                "project/jupiter-auth/resources/bootstrap.yml.ftl",
                "project/jupiter-auth/pom.xml.ftl",
                "project/jupiter-auth/java/JupiterAuthApplication.java",
        };
        freemarkeFiles(tmps, map, files);

    }

    private String[] createJavaAndResources4Module(String dir, String moduleName, boolean isNeedTest) {
        // 1 root
        String root = dir + File.separator + moduleName;
        String src = root + File.separator + "src";
        String main = src + File.separator + "main";
        String java = main + File.separator + "java";
        String resources = main + File.separator + "resources";
        String test = src + File.separator + "test";
        String testJava = test + File.separator + "java";
        try {
            if (isNeedTest) {
                mkdirs(new String[]{root, src, main, java, resources, test, testJava});
            } else {
                mkdirs(new String[]{root, src, main, java, resources});
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return new String[]{root, java, resources, testJava};
    }

    private String createJavaPackage4Module(String javaDir, String packageName) {
        // 2 packageName
        String[] packageNames = packageName.split("\\."); // .需要做转义

        String dirPackage = javaDir + "";
        for (String n : packageNames) {
            dirPackage = dirPackage + File.separator + n;
            try {
                new File(dirPackage).mkdir();
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        }
        return dirPackage;
    }

    private boolean mkdirs(String[] files) {
        for (String s : files) {
            new File(s).mkdir();
        }
        return true;
    }

    private void freemarkeFiles(String[] templateFiles, Map<String, Object> map, String[] destinationFiles) {
        int len = destinationFiles.length;
        for (int i = 0; i < len; i++) {
            try {
                GenUtils.freemarkerTemp2File(templateFiles[i], map, destinationFiles[i]);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        }
    }

    public void generateProject(Module module) {
        String projectDir = module.getDir() + File.separator + module.getName().toLowerCase();
        module.setPath(projectDir);
        new File(module.getPath()).mkdir();
        Map<String, Object> map = createHashMap(module);
        genModuleAuth(module, map); // auth

        System.out.println("============= Project:" + module.getName());
        System.out.println("== Path:" + module.getPath());

        System.out.println("==========================");

        createSystemUI(map, projectDir);
    }

    private void createSystemUI(Map<String, Object> map, String projectDir) {
        FileTree tree = new FileTree();
        tree.setName("jupiter-system-ui");
        tree.setPath(projectDir + File.separator + tree.getName());
        tree.setDir(true);
        tree.setTemplate("template/jupiter-system-ui");
        List<FileTree> trees = null;
        try {
            trees = JsonUtils.readJsonListFromClassPath("json/jupiter-system-ui.json", FileTree.class);
            tree.setList(trees);
            createModuleByFileTree(map, tree);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过文件数 创建/复制文件
     *
     * @param
     * @param
     * @param
     */
    private void createModuleByFileTree(Map<String, Object> map, FileTree fileTree) {
        // 路径是否存在 不存在 则创建
        if (fileTree.isDir()) {
            File file = new File(fileTree.getPath());
            if (!file.exists()) {
                file.mkdir();
            }
        } else {
            // 从Template复制到Path
            if (fileTree.isRes()) {
                copyFile(fileTree);
            } else {
                markeFile(map, fileTree);
            }
        }

        if (fileTree.getList() == null) {
            return;
        }
        for (FileTree item : fileTree.getList()) {
            item.setPath(fileTree.getPath() + File.separator + item.getName());
            item.setTemplate(fileTree.getTemplate() + File.separator + item.getName());
            createModuleByFileTree(map, item);
        }
    }

    private void copyFile(FileTree fileTree) {
        if (fileTree == null) {
            return;
        }
        String template = fileTree.getTemplate(), path = fileTree.getPath();

        ClassPathResource resource = new ClassPathResource(template);
        if (resource.exists()) {
            byte[] bytes = new byte[0];
            InputStream is = null;
            try {
                is = resource.getInputStream();
                Files.copy(is, Paths.get(path));
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("template not exists:" + template);
        }
    }

    private void markeFile(Map<String, Object> map, FileTree fileTree) {
        try {
            GenUtils.freemarkerTemp2File(fileTree.getTemplate(), map, fileTree.getPath());
        } catch (Exception e) {
            System.out.println("markeFile error:" + fileTree.getTemplate());
            throw new RuntimeException(e.getMessage());
        }
    }

}
